import { Injectable } from '@angular/core';
import { Http, Request, Response, Headers, RequestOptions, RequestMethod, RequestOptionsArgs } from '@angular/http';
import { HttpClient, HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import 'rxjs/add/operator/timeout';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import { Observable } from 'rxjs/Observable';
import { API_VERSION, DOMAIN, TOKEN_PREFIX } from '../../app.config';
import { BaseService } from './base-service';
import { IdentifiableEntity, BaseSearchCriteria } from '../../entities/entities';
import { LocalStorageService } from 'angular-2-local-storage';
import { TOKEN_STORAGE_KEY } from '../../app.config';
import { Identity, SearchRet } from '../../shared/model/defination';

export interface ExtRequestOptionsArgs extends RequestOptionsArgs {
    handle?: boolean,
    authHeaders?: boolean
}

// export interface SearchRet {
//     TotalPages: number;
//     PageNumber: number;
//     TotalRecords: number;
//     Items: Array<any>;
// }
// @Injectable()
export abstract class BaseGenericService<T extends Identity, S extends BaseSearchCriteria> extends BaseService {

    private static _pendingRequests: Array<string> = [];

    private _globalHeaders = new Headers({
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    });

    constructor(
        protected http: HttpClient,
        _api: string,
        protected _localStorageSerivce: LocalStorageService
    ) {
        super(_api);
    }

    public Id(): string {
        return '_' + Math.random().toString(36).substr(2, 9);
    }

    private _isSearchRet(data: any): boolean {
        data = data as SearchRet<T>;
        return typeof data.TotalPages !== 'undefined'
            && typeof data.PageNumber !== 'undefined'
            && typeof data.TotalRecords !== 'undefined'
            && typeof data.Items !== 'undefined';
    }


    private _handleResponse(res: any): T | Array<T> {
        if (!res) {
            return [];
        }
        else {
            return this._isSearchRet(res) ? res.Items : (res || {}) as T;
        }

    }

    public All(criteria?: any): Observable<T[]> {
        return this.http.post<Array<T>>(`${this.api}/all`, criteria);
    }

    public Create(entity: any): Observable<T> {
        return this.http.post<T>(this.api, entity);
    }

    public Update(entity: any): Observable<T> {
        return this.http.put<T>(`${this.api}/${entity.id}`, entity);
    }


    public Get(id: number): Observable<T> {
        return this.http.get<T>(`${this.api}/${id}`);
    }

    public Delete(id: number): Observable<T> {
        return this.http.delete<any>(`${this.api}/${id}`);
    }

    public SoftDelete(entity: any): Observable<T> {
        if (typeof entity.IsActive !== undefined) {
            entity.IsActive = false;
            return this.Update(entity);
        }
        return Observable.throw('can not be deleted');
    }

    public Search(criteria: S): Observable<SearchRet<T>> {
        return this.http.post<SearchRet<T>>(`${this.api}/search`, criteria);
    }
}